/*************************************************************************
                           pmPipeline  -  description
                             -------------------
    début                : 28 déc. 2009
    copyright            : (C) 2009 par nico
 *************************************************************************/

//---------- Interface de la classe <pmPipeline> (fichier pmPipeline.h) ------
#ifndef PIPELINE_H_
#define PIPELINE_H_

//--------------------------------------------------- Interfaces utilisées

#include "Port_in.h"
#include "pmElement.h"
#include "pmBox.h"
#include <string>
#include <list>
#include <set>
//------------------------------------------------------------- Constantes

//------------------------------------------------------------------ Types

//------------------------------------------------------------------------
// A pipeLine is a set of <Box> (including eventualy other pipelines)
// connected to each other.
// A pipeLine has inputs and outputs and optionaly constant boxes as entries
// the pipeLine is responsible for managing it's Boxes
//------------------------------------------------------------------------
template <class in_type = double, class out_type = in_type>
class pmPipeline : pmBox<in_type, out_type>
{
	//----------------------------------------------------------------- PUBLIC

public:
	//----------------------------------------------------- Méthodes publiques
	bool Compute();

	//-------------------------------------------- Constructeurs - destructeur
	pmPipeline(int nbInputs, int nbOutputs, int nbParams,
			std::list<pmBox*> firstBoxes, std::list<pmBox*> otherBoxes );

	virtual ~pmPipeline ( );
	// Mode d'emploi :
	//
	// Contrat :
	//

	//------------------------------------------------------------------ PRIVE

protected:
	//----------------------------------------------------- Méthodes protégées

	//----------------------------------------------------- Attributs protégés
	int m_nbBoxes;
	std::list<pmBox*> m_entries;
	std::list<pmBox*> m_boxList;

};







/********************************************************************
 *		Implementation
 *
 *********************************************************************/
using namespace std;

//--------------------------------------------------------- Public methods

bool pmPipeline<in_type, out_type>::Compute()
{
	//TODO check if  "set = list" is a correct syntax
	set<Box*> greyBoxes = m_entries;
	// the grey list contains the next boxes to be run,
	// i.e the ones that are next an already run box,
	// which means that one input at least is computed
	// but maybe not all of them.
	set<Box*> whiteBoxes = m_boxList;
	// the white list contains all the not-yet-run-boxes exept
	// from the ones in the grey list

	while(whiteBoxes.size()+greyBoxes.size() >= 0)
	{	//while there are boxes to run
		for(set<Box*>::const_iterator it = greyBoxes.begin(); it != greyBoxes.end() ; it++)
		{	// loop through the grey list
			if(it->CheckConnexions())//if the box is ready to be run
			{
				it->run(); // ..well let it run
				set<Box*> nextb = it->GetNextBoxes(); //for each box connect to this one...
				greyBoxes.insert(nextb.begin(), nextb.end()); //...insert it on the grey list
				greyBoxes.erase(it);// then remove the box from the greylist
			}
		}
	}
	return true; // TODO handle eventual errors
}


template <class in_type, class out_type> std::string pmPipeline::GetType()
{
	return "pipeline";
}



template <class in_type, class out_type> pmPipeline::pmPipeline(int nbInputs, int nbOutputs, int nbParams,
			std::list<Box*> firstBoxes, std::list<Box*> otherBoxes )
:pmBox<in_type, out_type>::pmBox(nbInputs, nbOutputs, nbParams)
{
	//TODO call Parent constructor
	// what happens if we call a list's copy constructor?
	// what if the originally copied list is deleted, will it delete
	// the second list's content ?
}

template <class in_type, class out_type> pmPipeline::~pmPipeline()
{
	for(list<Box*>::const_iterator it = m_boxList.begin(); it != m_boxList.end() ; it++)
	{
		delete *it;
	}
	for(list<Box*>::const_iterator it = m_entries.begin(); it != m_entries.end() ; it++)
	{
		delete *it;
	}
// TODO call parent destructor;
}




#endif // PIPELINE_H_

